package weiyao.xinxidasai.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import weiyao.xinxidasai.DTO.Result;
import weiyao.xinxidasai.DTO.versionDTO;
import weiyao.xinxidasai.Utils.ThreadLocal.UserHolder;
import weiyao.xinxidasai.DTO.versioncreate;
import weiyao.xinxidasai.config.Redis.BloomFilter;
import weiyao.xinxidasai.config.Redis.RedisCache;
import weiyao.xinxidasai.config.Redis.RequestValidator;
import weiyao.xinxidasai.mapper.FilesMapper;
import weiyao.xinxidasai.mapper.VersionMapper;
import weiyao.xinxidasai.pojo.FFiles;
import weiyao.xinxidasai.pojo.Version;
import weiyao.xinxidasai.service.VersionService;
import java.util.concurrent.ThreadLocalRandom;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;



@Service
public class VersionServiceImpl implements VersionService {
    private static final String RATE_LIMIT_KEY = "version_limit:%s";

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private versioncreate versionCreate;

    @Autowired
    private VersionMapper versionMapper;

    @Autowired
    private FilesMapper filesMapper;

    @Autowired
    private RedisCache redisCache;


    @Autowired
    private BloomFilter bloomFilter;

    // 使用白名单过滤器
    @Autowired
    @Qualifier("versionBloomFilter")
    private BloomFilter versionBloomFilter;

    // 使用黑名单校验器
    @Autowired
    private RequestValidator requestValidator;




    @Transactional
    @Override
    public Result createVersion() {
        Long userId = UserHolder.getUser().getUserId();
        String limitKey = String.format(RATE_LIMIT_KEY, userId);

        // 频率限制检查
        Long count = redisTemplate.opsForValue().increment(limitKey, 1);
        if (count != null && count > 5) {
            return Result.fail("今日生成次数已达上限");
        }
        if (count == 1) {
            redisTemplate.expire(limitKey,
                    ThreadLocalRandom.current().nextInt(82800, 86400),
                    TimeUnit.SECONDS);
        }

        // 生成版本信息
        Version version = versionCreate.createVersion();
        versionMapper.insert(version);

        // 存储到用户专属哈希表
        String userKey = "versions_user_" + userId;
        redisTemplate.expire(userKey, 30, TimeUnit.DAYS);
        redisTemplate.opsForHash().put(userKey,
                version.getVersionId().toString(),
                convertVersionDTOToJson(convertToDTO(version)));
        redisTemplate.expire(userKey, 30, TimeUnit.DAYS);
        redisTemplate.expire(limitKey, 86400, TimeUnit.SECONDS);
        // 更新布隆过滤器
        versionBloomFilter.add(version.getVersionNo());

        return Result.ok();
    }


    @Override
    public List<versionDTO> getAllVersionsByUserId(Long userId) {
        String outerKey = "versions_user_" + userId;
        Map<Object, Object> cached = redisCache.getCacheMap(outerKey);

        // 缓存存在时返回缓存数据
        if (cached != null && !cached.isEmpty()) {
            System.out.println("查询缓存");
            Map<String, Object> typedCache = new HashMap<>();
            for (Map.Entry<Object, Object> entry : cached.entrySet()) {
                typedCache.put(entry.getKey().toString(), entry.getValue());
            }

            return typedCache.values().stream()
                    .map(json -> parseJsonToVersionDTO( json.toString()))
                    .collect(Collectors.toList());
        }

        // 缓存不存在时查询数据库并更新缓存
        List<versionDTO> versionDTOS = versionMapper.selectAllVersionsByUserId(userId);
        Map<String, Object> hashEntries = versionDTOS.stream()
                .collect(Collectors.toMap(
                        dto -> String.valueOf(dto.getVersionId()),
                        this::convertVersionDTOToJson
                ));

        // 设置随机过期时间（20-30分钟）
        redisCache.setCacheMap(outerKey, hashEntries, 20, 30, TimeUnit.MINUTES);

        return versionDTOS;
    }

    @Override
    public List<String> getAllVersionIDByUserId(Long userId) {
        return versionMapper.selectAllVersionIDByUserId(userId);
    }


    @Override
    public List<versionDTO> getVersionById(String versionNo) {

        // 2. 参数安全校验
        if (!requestValidator.isParameterValid(versionNo)) {
            return Collections.emptyList();
        }
        // 使用白名单预检查
//        if (!versionBloomFilter.mightContain(versionNo)) {
//            return Collections.emptyList(); // 快速返回
//        }
        String key = "version_" + versionNo;
        System.out.println(key);
        String lockKey = "lock:" + key;
        try {
       // 3. 获取分布式锁
            if (!redisCache.tryLock(lockKey, 3, TimeUnit.SECONDS)) {
                Thread.sleep(50); // 减少等待时间
                return getVersionById(versionNo); // 递归重试
            }
       // 4. 二次缓存检查
            Object cached = redisCache.getCache(key);
            System.out.println(cached);
            if (cached != null) {
                if (RedisCache.NULL_OBJECT.equals(cached)) {
                    return Collections.emptyList();
                }
                return (List<versionDTO>) cached;
            }
       // 5. 数据库查询
            List<versionDTO> versions = versionMapper.getVersionByVersionNo(
                    versionNo, UserHolder.getUser().getUserId()
            );
            System.out.println("查询数据库");
        // 6. 缓存处理
            if (versions.isEmpty()) {
         // 防穿透：缓存空值
                redisCache.setCache(key, RedisCache.NULL_OBJECT, 30, TimeUnit.SECONDS);
                bloomFilter.add(versionNo); // 添加到布隆过滤器
                return Collections.emptyList();
            }
         // 7. 设置随机过期时间防止雪崩
            redisCache.setCacheWithRandomExpire(key, versions, 30, 60, TimeUnit.SECONDS);
            return versions;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return Collections.emptyList();
        } finally {
       // 确保解锁操作安全
            if (redisCache.isLocked(lockKey)) {
                redisCache.unlock(lockKey);
            }
        }
    }






    @Override
    public Result updateVersion(Long versionId, String versionNo) {
        if (versionId == null || versionNo == null) {
            return Result.fail("参数不能为空");
        }

        if (!requestValidator.isParameterValid(versionNo)) {
            return Result.fail("非法参数");
        }

        Version version = versionMapper.getVersionByVersionId(versionId);

        if (version.getVersionNo().equals(versionNo)) {
            return Result.fail("不能与原名字相同");
        }

        Long userId = UserHolder.getUser().getUserId();
        int i = versionMapper.updateVersion(versionId, versionNo, userId);
        if (i > 0) {
            // 更新缓存
            redisCache.deleteCache("version_" + versionId);
            String outerKey = "versions_user_" + userId;
            versionDTO versionnow = versionMapper.getVersionDTOByVersionId(versionId);
            // 删除哈希表中的特定字段
            redisCache.deleteHashCache(outerKey, versionId);
          //需要更新outerkey中的versionId，将versionnow的versionId放入hashvalue中的key json放入value
            String jsonValue = convertVersionDTOToJson(versionnow);

            // 2. 更新 Redis Hash 中的字段值
            redisCache.setHashCache(outerKey, versionId.toString(), jsonValue);

            versionBloomFilter.add(versionNo);
            return Result.ok();
        }
        return Result.fail("更新失败");
    }

    @Transactional
    @Override
    public Result deleteVersionById(Long versionId) {
        // 1. 参数校验
        if (versionId == null) {
            return Result.fail("参数不能为空");
        }

        String cacheKey = "version_" + versionId;
        System.out.println("versionId = " + versionId);

        // 3. 关联文件检查
        List<FFiles> files = filesMapper.findFilesByversionId(versionId);
        if (!files.isEmpty()) {
            // 更新缓存防止击穿
            redisCache.setCache(cacheKey, files, 30, TimeUnit.SECONDS);
            return Result.fail("有文件用此密钥加密 无法删除");
        }

        // 4. 执行删除操作
        int result = versionMapper.deleteVersionById(versionId);
        System.out.println("result = " + result);
        if (result > 0) {
            // 5. 缓存双删策略
            Long userId = UserHolder.getUser().getUserId();
            String outerKey = "versions_user_" + userId;

            // 删除哈希表中的特定字段
            redisCache.deleteHashCache(outerKey, versionId);

            new Thread(() -> {
                try {
                    Thread.sleep(500);
                    redisCache.deleteHashCache(outerKey, versionId);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }).start();
            return Result.ok();
        }
        return Result.fail("删除失败");
    }










    private final ObjectMapper objectMapper = new ObjectMapper();

    private String convertVersionDTOToJson(versionDTO dto) {
        try {
            return objectMapper.writeValueAsString(dto);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("JSON序列化失败", e);
        }
    }

    private versionDTO parseJsonToVersionDTO(String json) {
        try {
            return objectMapper.readValue(json, versionDTO.class);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("JSON反序列化失败", e);
        }
    }
    private versionDTO convertToDTO(Version version) {
        versionDTO dto = new versionDTO();
        dto.setVersionId(version.getVersionId());
        dto.setVersionNo(version.getVersionNo()); // 对密钥进行脱敏
        dto.setCreateTime(version.getCreateTime());
        return dto;
    }

}





